#pragma once

#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <unistd.h>
#include "thread.hpp"
#include "lockGuard.hpp"
#include "log.hpp"

//总结：视频听课处理三个不理解的内容；总结线程池的实现逻辑；复盘代码的实现并写出相应总结

const int g_thread_num =3;
template<class T>
class ThreadPool
{

private:
    std::vector<Thread*>thread_;//多个线程存储数组
    int num_;//线程名
    std::queue<T> task_queue_;//任务队列

    static ThreadPool<T>*thread_ptr;
    static pthread_mutex_t mutex;

private:
    ThreadPool(int thread_num = g_thread_num):num_(thread_num)
    {
        //构造线程池
        pthread_mutex_init(&lock,nullptr);
        pthread_cond_init(&cond,nullptr);
        for(int i =0;i<=num_;i++)
        {
            thread_.push_back(new Thread(i,routine,this));
        }
    }
    //禁止线程的拷贝构造以及赋值操作:重点1
    ThreadPool(const ThreadPool<T>&other) = delete;
    const ThreadPool<T>&operator = (const ThreadPool<T>&other) = delete;

public:
    pthread_mutex_t*getMutex()
    {
        return &lock;
    }
    bool isEmpty()
    {
        return task_queue_.empty();
    }
    void waitCond
    {
        pthread_cond_wait(&cond,&lock);
    }
    T getTask()
    {
        T t = task_queue_.front();
        task_queue_.pop();
        return t;
    }

public:
    ~ThreadPool()
    {
        //销毁线程池中的所有线程，同时释放其锁和条件变量
        for(auto&iter:thread_)
        {
            iter->join();
            delete iter;
        }
        pthread_mutex_destroy(&lock);
        pthread_cond_destroy(&cond);
    }

public:
    //线程池中的基本操作
    static ThreadPool<T>*getThreadPool(int num = g_thread_num)
    {
        //如果线程池中没有线程(待处理)
        if(nullptr == thread_ptr)
        {
            lockGuard lockGuard(&mutex);
            if(nullptr == thread_ptr)
            {
                thread_ptr = new ThreadPool<T>(num);
            }
        }

        return thread_ptr;
    }

    //启动线程池
    void run()
    {
        for(auto&iter:thread_)
        {
            iter->start();
            logMessage(NORMAL, "%s %s", iter->name().c_str(), "启动成功");
        }
    }

    //线程默认执行的任务(消费过程)(待处理：args参数在其中起到什么作用，以及转换原则是什么)
    //核心逻辑：取任务并执行任务
    //static函数使用原因：因为是类内方法，参数含有this指针，参数与函数执行期间不吻合
    //静态成员函数：只能够使用静态成员和静态方法，无法使用类内的成员变量和方法；
    //总结（静态无法访问成员，但是类内成员可以访问静态函数） 
    static void*routine(void*args)
    {
        ThreadData*td = (ThreadData*)args;
        //因为上面传入的是this指针，将this指针转换成线程池对象
        ThreadPool<T>*tp = (ThreadPool<T>*)td->args_;

        while(true)
        {
            //实现逻辑：加锁、获取任务、处理任务
            T task;
            {
                lockGuard lockGuard(tp->getMutex());
                while(tp->isEmpty())
                {
                    //如果此时是空的时候，需要释放自己持有的锁，以供其他线程进行使用
                    tp.waitCond();
                }
                task = tp->getTask();
            }
            task(td->name_);
        }
    }

    void push_back(const T&task)
    {
        lockGuard lockGuard(&lock);
        task_queue_.push(task);
        pthread_cond_signal(&cond);
    }
};

//
template<typename T>
ThreadPool<T>*ThreadPool<T>::thread_ptr = nullptr;

template <typename T>
pthread_mutex_t ThreadPool<T>::mutex = PTHREAD_MUTEX_INITIALIZER;